package com.example.patient.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.example.common.entity.CMS;
import com.example.common.entity.ClientBaseInfo;
import com.example.common.entity.MsgConfig;
import com.example.common.support.ApiException;
import com.example.common.utils.*;
import com.example.patient.dto.req.*;
import com.example.patient.dto.resp.*;
import com.example.patient.jpa.CMSRepository;
import com.example.patient.jpa.ClientBaseInfoRepository;
import com.example.patient.jpa.MsgConfigRepository;
import com.example.patient.properties.WxProp;
import com.example.patient.service.LoginService;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import java.net.InetAddress;
import java.util.Collections;
import java.util.Date;

/**
 * @Author wxy
 * @Date 2021/1/18 10:36
 * @Version 1.0
 */
@Service
public class LoginServiceImpl implements LoginService {
    @Resource
    private UIDUtils uidUtils;
    @Resource
    private HxUtils hxUtils;
    @Resource
    private WxProp wxProp;
    @Resource
    private WxMaService wxMaService;

    @Resource
    private CMSRepository cmsRepository;
    @Resource
    private ClientBaseInfoRepository clientBaseInfoRepository;
    @Resource
    private MsgConfigRepository msgConfigRepository;

    /**
     * 登录信息
     */
    @Override
    public GetClientInfoResp getClientInfo() {
        Long uid = uidUtils.getUid();
        CMS cms = cmsRepository.findByTypes(2);
        CheckUtils.checkNull(cms, new ApiException(1, "未查询到数据"));
        String txt = cms.getNContent();

        GetClientInfoResp resp = new GetClientInfoResp();
        resp.setUid(uid);
        resp.setProtocol(txt);

        if (uid != 0L) {
            ClientBaseInfo clientBaseInfo = clientBaseInfoRepository.findById(uid).orElse(null);
            if (null != clientBaseInfo) {
                resp.setOpenId(clientBaseInfo.getOpenId());
                resp.setPhone(clientBaseInfo.getPhone());
                resp.setNickName(clientBaseInfo.getNickName());
                resp.setHeader(clientBaseInfo.getHeader());
                resp.setHxId(clientBaseInfo.getHxId());
                resp.setHxPwd(clientBaseInfo.getHxPwd());
            }
        }
        return resp;
    }

    /**
     * 微信信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public GetWcInfoResp GetWcInfo(GetWcInfoReq req) {
        GetWcInfoResp resp = new GetWcInfoResp();
        CheckUtils.checkNull(req, new ApiException(1, "对象不能为空"));
        String code = CheckUtils.checkNullReturn(req.getCode(), new ApiException(1, "微信code不能为空"));

        WxMpUser wxMpUser;
        String openId;
        try {
            WxMpService wxMpService = new WxMpServiceImpl();

            WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
            configStorage.setAppId(wxProp.getWxPublicAppId());
            configStorage.setSecret(wxProp.getWxPublicAppSecret());
            wxMpService.setWxMpConfigStorage(configStorage);

            WxOAuth2AccessToken wxOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
            openId = wxOAuth2AccessToken.getOpenId();
            wxMpUser = wxMpService.getUserService().userInfo(openId, "zh_CN");
        } catch (WxErrorException e) {
            resp.setSess(false);
            return resp;
        }

        if(openId == null || openId.isEmpty()){
            resp.setSess(false);
            return resp;
        }
        ClientBaseInfo clientBaseInfo = clientBaseInfoRepository.findFirstByOpenId(openId);
        
        if (null == clientBaseInfo) {
            Date date = new Date();
            clientBaseInfo = new ClientBaseInfo();
            clientBaseInfo.setUid(IdUtils.generateId());
            clientBaseInfo.setOpenId(openId);
            clientBaseInfo.setUnionId(null);
            clientBaseInfo.setPhone(null);
            clientBaseInfo.setRegTime(date);
            clientBaseInfo.setNickName(wxMpUser.getNickname());
            clientBaseInfo.setHeader(wxMpUser.getHeadImgUrl());
            clientBaseInfo.setHxId(openId + wxProp.getWxPublicAppId());
            String hxPwd = hxUtils.enCodePwd(clientBaseInfo.getHxId());
            hxUtils.createHXID(clientBaseInfo.getHxId(),hxPwd);
            clientBaseInfo.setHxPwd(hxPwd);
            clientBaseInfo.setIsReceive(Boolean.TRUE);
            clientBaseInfo.setCodeTime(date);
            clientBaseInfoRepository.save(clientBaseInfo);
        }
        resp.setSess(true);
        resp.setUid(clientBaseInfo.getUid());
        resp.setPhone(clientBaseInfo.getPhone());
        resp.setNickName(clientBaseInfo.getNickName());
        resp.setHeader(clientBaseInfo.getHeader());
        resp.setHxId(clientBaseInfo.getHxId());
        resp.setHxPwd(clientBaseInfo.getHxPwd());
        return resp;
    }

    /**
     * 发送短信
     */
    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public SendCodeResp SendCode(SendCodeReq req) {
        CheckUtils.checkNull(req, new ApiException(1, "对象不能为空"));
        String tel = CheckUtils.checkNullReturn(req.getTel(), new ApiException(1, "电话不能为空"));
        Long uid = uidUtils.getUid();

        Long count = clientBaseInfoRepository.countByPhoneAndUidNotIn(tel, uid);
        if (count > 0) {
            throw new ApiException(1, "手机号已注册");
        }

        MsgConfig msgConfig = msgConfigRepository.findById("Client_LoginCode").orElseThrow(() -> new ApiException(1, "未查询到数据"));
        String templateId = msgConfig.getTemplateId();
        String code = RandomUtil.randomNumbers(6);
        SmsUtils.sendSmsMessage(tel, Collections.singletonList(code), templateId);

        ClientBaseInfo clientBaseInfo = clientBaseInfoRepository.findById(uid).orElseThrow(() -> new ApiException(1, "没有用户，请重新授权登录"));
        clientBaseInfo.setPhone(tel);
        clientBaseInfo.setCode(code);
        clientBaseInfo.setCodeTime(DateUtil.offsetMinute(new Date(), 10));
        clientBaseInfoRepository.save(clientBaseInfo);

        SendCodeResp resp = new SendCodeResp();
        resp.setSend(Boolean.TRUE);
        return resp;
    }

    /**
     * 短信登录
     */
    @Override
    public DoSMSLoginResp DoSMSLogin(DoSMSLoginReq req) {
        CheckUtils.checkNull(req, new ApiException(1, "对象不能为空"));
        String tel = CheckUtils.checkNullReturn(req.getTel(), new ApiException(1, "电话不能为空"));
        String smsCode = CheckUtils.checkNullReturn(req.getSmscode(), new ApiException(1, "短信验证码不能为空"));

        ClientBaseInfo clientBaseInfo = clientBaseInfoRepository.findFirstByPhone(tel);
        if (null == clientBaseInfo) {
            throw new ApiException(1, "该手机号未注册");
        }
        if (new Date().after(clientBaseInfo.getCodeTime())) {
            throw new ApiException(1, "验证码已失效");
        }

        String hostAddress = null;
        try {
            InetAddress localHost = InetAddress.getLocalHost();
            hostAddress = localHost.getHostAddress();//获取IP地址
        }catch (Exception e){
            
        }

        if(hostAddress != null && hostAddress.indexOf("192.168.1.") != -1 && hostAddress.indexOf("localhost") != -1 ){
            if (!smsCode.equals(clientBaseInfo.getCode())) {
                throw new ApiException(1, "验证码错误");
            }
        }

        
        DoSMSLoginResp resp = new DoSMSLoginResp();
        resp.setLogin(Boolean.TRUE);
        return resp;
    }

    /**
     * 通过code换取openid和UID (正式）
     */
    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public getWxInfoRResp getWxInfoR(getWxInfoRReq req) {
        CheckUtils.checkNull(req, new ApiException(1, "对象不能为空"));
        String code = CheckUtils.checkNullReturn(req.getCode(), new ApiException(1, "微信code不能为空"));

        String openId;
        try {
            WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.getUserService().getSessionInfo(code);
            openId = wxMaJscode2SessionResult.getOpenid();            
        } catch (WxErrorException e) {
            throw new ApiException(1, e.getMessage());
        }

        ClientBaseInfo clientBaseInfo = clientBaseInfoRepository.findFirstByOpenId(openId);
        if (null == clientBaseInfo) {
            Date date = new Date();
            clientBaseInfo = new ClientBaseInfo();
            clientBaseInfo.setUid(IdUtils.generateId());
            clientBaseInfo.setOpenId(openId);
            clientBaseInfo.setUnionId(null);
            clientBaseInfo.setPhone(null);
            clientBaseInfo.setRegTime(date);
            clientBaseInfo.setNickName(null);
            clientBaseInfo.setHeader(null);
            clientBaseInfo.setHxId(openId + wxProp.getWxAppletsAppId());
            String hxPwd = hxUtils.enCodePwd(clientBaseInfo.getHxId());
            try {
                hxUtils.createHXID(clientBaseInfo.getHxId(), hxPwd);
            } catch (Exception e) {
                
            }
            clientBaseInfo.setHxPwd(hxPwd);
            clientBaseInfo.setIsReceive(Boolean.TRUE);
            clientBaseInfo.setCodeTime(date);
            clientBaseInfoRepository.save(clientBaseInfo);
        }
        else if(clientBaseInfo.getHxId() == null || clientBaseInfo.getHxId().isEmpty()){
            clientBaseInfo.setHxId(openId + wxProp.getWxAppletsAppId());
            String hxPwd = hxUtils.enCodePwd(clientBaseInfo.getHxId());
            try {
                hxUtils.createHXID(clientBaseInfo.getHxId(), hxPwd);
            } catch (Exception e) {
                
            }
            clientBaseInfo.setHxPwd(hxPwd);
            clientBaseInfoRepository.save(clientBaseInfo);
        }
        getWxInfoRResp getWxInfoRResp = new getWxInfoRResp();
        getWxInfoRResp.setUid(clientBaseInfo.getUid());
        getWxInfoRResp.setNickName(clientBaseInfo.getNickName());
        getWxInfoRResp.setPhone(clientBaseInfo.getPhone());
        getWxInfoRResp.setHeader(clientBaseInfo.getHeader());
        getWxInfoRResp.setHxId(clientBaseInfo.getHxId());
        getWxInfoRResp.setHxPwd(clientBaseInfo.getHxPwd());
        return getWxInfoRResp;
    }

    /**
     * 获取电话
     */
    @Override
    public GetUserTelResp GetUserTel(GetUserTelReq req) {
        CheckUtils.checkNull(req, new ApiException(1, "对象不能为空"));
        String code = CheckUtils.checkNullReturn(req.getCode(), new ApiException(1, "微信code不能为空"));
        String encryptedData = CheckUtils.checkNullReturn(req.getEncryptedData(), new ApiException(1, "加密数据不能为空"));
        String iv = CheckUtils.checkNullReturn(req.getIv(), new ApiException(1, "加密数据的种子不能为空"));

        String phone;
        try {
            WxMaJscode2SessionResult wxMaJscode2SessionResult = wxMaService.getUserService().getSessionInfo(code);
            WxMaPhoneNumberInfo wxMaPhoneNumberInfo = wxMaService.getUserService().getPhoneNoInfo(wxMaJscode2SessionResult.getSessionKey(), encryptedData, iv);
            phone = wxMaPhoneNumberInfo.getPurePhoneNumber();
        } catch (WxErrorException e) {
            throw new ApiException(1, e.getMessage());
        }

        GetUserTelResp resp = new GetUserTelResp();
        resp.setPhone(phone);
        return resp;
    }
}
